package cz.muni.fi.pa165.musiclibrary.musiclibraryweb.pages.album;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import org.apache.commons.lang3.StringUtils;
import org.apache.wicket.RestartResponseException;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.markup.html.AjaxLink;
import org.apache.wicket.event.IEvent;
import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow;
import org.apache.wicket.markup.head.CssHeaderItem;
import org.apache.wicket.markup.head.IHeaderResponse;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.image.Image;
import org.apache.wicket.markup.html.link.BookmarkablePageLink;
import org.apache.wicket.markup.html.link.Link;
import org.apache.wicket.markup.html.list.ListItem;
import org.apache.wicket.markup.html.list.ListView;
import org.apache.wicket.model.StringResourceModel;
import org.apache.wicket.request.mapper.parameter.PageParameters;
import org.apache.wicket.request.resource.CssResourceReference;
import org.apache.wicket.spring.injection.annot.SpringBean;

import cz.muni.fi.pa165.musiclibrary.api.service.IAlbumService;
import cz.muni.fi.pa165.musiclibrary.api.service.ISongService;
import cz.muni.fi.pa165.musiclibrary.api.service.auth.IUser;
import cz.muni.fi.pa165.musiclibrary.api.service.dto.IAlbumDTO;
import cz.muni.fi.pa165.musiclibrary.api.service.dto.IArtistDTO;
import cz.muni.fi.pa165.musiclibrary.api.service.dto.IGenreDTO;
import cz.muni.fi.pa165.musiclibrary.api.service.dto.ISongDTO;
import cz.muni.fi.pa165.musiclibrary.musiclibraryweb.MusicLibrarySession;
import cz.muni.fi.pa165.musiclibrary.musiclibraryweb.components.AlbumFormPanel;
import cz.muni.fi.pa165.musiclibrary.musiclibraryweb.components.ConfirmationLink;
import cz.muni.fi.pa165.musiclibrary.musiclibraryweb.components.FormSubmittedEvent;
import cz.muni.fi.pa165.musiclibrary.musiclibraryweb.components.image.ImageResource;
import cz.muni.fi.pa165.musiclibrary.musiclibraryweb.pages.AbstractMusicLibraryPage;
import cz.muni.fi.pa165.musiclibrary.musiclibraryweb.pages.artist.ArtistPage;
import cz.muni.fi.pa165.musiclibrary.musiclibraryweb.pages.genre.GenrePage;
import cz.muni.fi.pa165.musiclibrary.musiclibraryweb.pages.search.SearchPage;
import cz.muni.fi.pa165.musiclibrary.musiclibraryweb.pages.song.SongPage;

/**
 *
 * @author Maros Kucbel
 * @date 2012-11-23T21:18:57+0100
 */
public final class AlbumPage extends AbstractMusicLibraryPage {
    
    @SpringBean
    private ISongService songService;
    @SpringBean
    private IAlbumService albumService;
    
    public AlbumPage() {
        this(new PageParameters());
    }
    
    public AlbumPage(final PageParameters pageParameters) {
        super(pageParameters);
    }

    @Override
    public void renderHead(IHeaderResponse response) {
      
        response.render(CssHeaderItem.forReference(new CssResourceReference(AlbumPage.class, "AlbumPage.css")));
        super.renderHead(response);
    }
    
    @Override
    protected void onInitialize() {
        super.onInitialize();
        this.initComponents();
    }
    
    public void initComponents() {
        PageParameters pageParameters = this.getPageParameters();
        final Long albumId = pageParameters.get("id").toOptionalLong();
        if (albumId == null) {
            throw new RestartResponseException(SearchPage.class);
        }
        final IAlbumDTO album = getAlbum(albumId);
        if (album == null) {
            throw new RestartResponseException(SearchPage.class);
        }
        List<ISongDTO> songs = getSongs(album);
        
        add(new Label(AlbumPage.ComponentIDs.ALBUM_TITLE, album.getTitle()));
        String releaseDate = album.getReleaseDate() != null ? String.valueOf(album.getReleaseDate().getYear()) : "";
        add(new Label(AlbumPage.ComponentIDs.ALBUM_DATE, releaseDate ).setVisible(StringUtils.isNotBlank(releaseDate)) );
        ImageResource imageResource = new ImageResource(album.getAlbumArt(), "jpg");
        Image image = new Image(ComponentIDs.ALBUM_IMAGE, imageResource);
        image.setVisible(album.getAlbumArt() != null);
        this.add(image);
        
        List<IGenreDTO> genres = new ArrayList<IGenreDTO>();
        List<IArtistDTO> artists = new ArrayList<IArtistDTO>();
        for(ISongDTO s: songs){
            if (!artists.contains(s.getArtist())){
                artists.add(s.getArtist());
            }
            if (!genres.contains(s.getGenre())){
                genres.add(s.getGenre());
            }
            
        }
       
        ListView<IGenreDTO> genresView = new ListView<IGenreDTO>(ComponentIDs.ALBUM_GENRES, genres) {

            @Override
            protected void populateItem(ListItem<IGenreDTO> item) {
                IGenreDTO genre = item.getModelObject();
                PageParameters params = new PageParameters();
                params.add("id", genre.getIdGenre().toString());
                Link<Void> genreLink = new BookmarkablePageLink<Void>(ComponentIDs.GENRE_LINK, GenrePage.class, params);
                genreLink.add(new Label(ComponentIDs.GENRE_LINK_NAME, genre.getName()));
                item.add(genreLink);
            }
        };
        genresView.setVisible(!genres.isEmpty());
        this.add(genresView);
        
       
        ListView<IArtistDTO> artistsView = new ListView<IArtistDTO>(ComponentIDs.ARTISTS_VIEW, artists) {

            @Override
            protected void populateItem(ListItem<IArtistDTO> item) {
                IArtistDTO artist = item.getModelObject();
                PageParameters parameters = new PageParameters();
                parameters.add("id", artist.getIdArtist().toString());
                Link<Void> artistLink = new BookmarkablePageLink<Void>(ComponentIDs.ARTIST_LINK, ArtistPage.class, parameters);
                artistLink.add(new Label(ComponentIDs.ARTIST_LINK_NAME, artist.getName()));
                item.add(artistLink);
            }
        };
        artistsView.setVisible(!artists.isEmpty());
        add(artistsView);
  
        
        ListView<ISongDTO> songsView = new ListView<ISongDTO>(ComponentIDs.SONGS_VIEW, songs) {

            @Override
            protected void populateItem(ListItem<ISongDTO> item) {
                ISongDTO song = item.getModelObject();
              
                PageParameters params = new PageParameters();
                params.add("id", song.getIdSong().toString());
                Link<Void> songLink = new BookmarkablePageLink<Void>(ComponentIDs.SONG_LINK, SongPage.class, params);
                songLink.add(new Label(ComponentIDs.SONG_LINK_NAME, song.getTitle()));
                String trackNumberLabel = song.getTrackNumber() == null ? null : song.getTrackNumber().toString();
                songLink.add(new Label(ComponentIDs.SONG_LINK_TRACK_NUMBER, trackNumberLabel));
                item.add(songLink);
            }
        };
        this.add(songsView);
        
        MusicLibrarySession session = MusicLibrarySession.get();
        final ModalWindow albumWindow = new ModalWindow(ComponentIDs.EDIT_ALBUM_MODAL) {

            @Override
            public void show(AjaxRequestTarget target) {
                this.setContent(new AlbumFormPanel(this.getContentId(), album));
                super.show(target);
            }
        };
        this.add(albumWindow);
        albumWindow.setTitle(new StringResourceModel("AlbumPage.editAlbum.modal.title", this, null));
        albumWindow.setMinimalWidth(500);
        albumWindow.setCssClassName(ModalWindow.CSS_CLASS_GRAY);
        AjaxLink editAlbum = new AjaxLink(ComponentIDs.EDIT_ALBUM_MODAL_LINK) {

            @Override
            public void onClick(AjaxRequestTarget target) {
                albumWindow.show(target);
            }

            @Override
            public void onEvent(IEvent<?> event) {
                if (albumWindow.isShown() && event.getPayload() instanceof FormSubmittedEvent) {
                    FormSubmittedEvent submitted = (FormSubmittedEvent) event.getPayload();
                    albumWindow.close(submitted.getTarget());
                    AlbumPage.this.setResponsePage(AlbumPage.class, AlbumPage.this.getPageParameters());
                }
            }
            
        };
        editAlbum.setVisible(session.isAuthorized());
        this.add(editAlbum);
        
        String deleteMessage = new StringResourceModel("AlbumPage.deleteAlbum.confirmation.message", this, null).getObject();
        ConfirmationLink<IAlbumDTO> deleteAlbum = new ConfirmationLink<IAlbumDTO>(ComponentIDs.DELETE_ALBUM_LINK, deleteMessage) {

            @Override
            public void onClick(AjaxRequestTarget target) {
                try {
                    IUser user = MusicLibrarySession.get().getUser();
                    String userName = user != null ? user.getUserName() : null;
                    AlbumPage.this.albumService.delete(album, userName);
                    this.setResponsePage(SearchPage.class);
                } catch (Exception ex) {
                    String errorMessage = new StringResourceModel("database.delete.error", this, null).getObject();
                    target.appendJavaScript("alert('" + errorMessage + "');");
                }
            }
        };
        deleteAlbum.setVisible(session.isAuthorized());
        this.add(deleteAlbum);
    }
        
    
    private IAlbumDTO getAlbum(Long albumId) {
        return this.albumService.getById(albumId);
    }
    
     /**
     * Returns list of songs, on album
     */
    private List<ISongDTO> getSongs(IAlbumDTO album) {
        List<ISongDTO> songs = new ArrayList<ISongDTO>();
        songs.addAll(this.songService.getByAlbum(album));
        Collections.sort(songs, new CustomComparator());
        
        return songs;
    }
    
    /** Identifiers of added components. */
    private static final class ComponentIDs {
        private static final String ALBUM_TITLE = "albumTitle";
        private static final String ALBUM_DATE = "albumDate";
        private static final String ALBUM_GENRES = "albumGenres";
        private static final String ALBUM_IMAGE = "albumImage";
        private static final String GENRE_LINK = "genreLink";
        private static final String GENRE_LINK_NAME = "genreLinkName";
        private static final String SONGS_VIEW = "songsView";
        private static final String SONG_LINK = "songLink";
        private static final String SONG_LINK_NAME = "songLinkName";
        private static final String SONG_LINK_TRACK_NUMBER = "songLinkTrackNumber";
        private static final String ARTIST_LINK = "artistLink";
        private static final String ARTIST_LINK_NAME = "artistLinkName";
        private static final String ARTISTS_VIEW = "artistsView";
        
        private static final String EDIT_ALBUM_MODAL = "editAlbumModal";
        private static final String EDIT_ALBUM_MODAL_LINK = "editAlbumModalLink";
        
        private static final String DELETE_ALBUM_LINK = "deleteAlbumLink";
    }
    
    public class CustomComparator implements Comparator<ISongDTO> {
        @Override
        public int compare(ISongDTO o1, ISongDTO o2) {
            if(o1.getTrackNumber() != null && o2.getTrackNumber() != null) {
                return o1.getTrackNumber().compareTo(o2.getTrackNumber());
            } else if(o1.getTrackNumber() == null && o2.getTrackNumber() != null){
                return 1;
            } else if(o1.getTrackNumber() != null && o2.getTrackNumber() == null) {
                return -1;
            } else {
                return o1.getTitle().compareTo(o2.getTitle());
            }
        }
    }
}